import { Renderer, ScopedContext, FormItem } from 'amis';
import { BasePlugin, EditorManager, getSchemaTpl } from 'amis-editor';
import { IObject, emptyFn, udp } from '@cscec/udp-ui';
import React from 'react';
import type { IScopedContext } from 'amis';
import { generateProps } from '../util';

export interface IOpts {
  /**
     * 是否需要注册plugin，false时表示只注册render渲染器，不注册plugin
     */
  isPlugin?: boolean;
  /**
     * 组件唯一标识，必须小写
     */
  type: string;
  /**
     * 组件分组
     */
  group?: string;

  /**
     * 组件名称
     */
  name: string;
  /**
     * 组件描述
     */
  description?: string;

  /**
     * 组件图标
     */
  icon?: string;

  /**
     * 右侧面板title
     */
  panelTitle?: string;

  /**
     * 右侧面板定义
     */
  panelBody?: Array<IObject>;

  /**
     * 右侧面板tab页内容
     */
  panelTabs?: Array<IObject>;

  /**
     * 组件的名称，调试用
     */
  dislayName?: string;
  /**
     * 是否系统组件
     */
  isBaseComponent?: boolean;
  [x: string]: any;
}

const rendererSet = new Set();

/**
 *
 * @param Cmp 函数组件
 * @param options IOpts
 */
export function wrapperRender(Cmp: React.FunctionComponent<{ outRef: React.ForwardedRef<any>;[x: string]: any }>, options: IOpts) {
  const {
    type, name, group, panelBodyCreator, panelBody, panelTabs, scaffold,
    isBaseComponent = true, groupType, isPlugin = true, designType,
    rendererName, displayName, events, isFormItem, previewSchema, renderApiCreator, ...payload
  } = options;

  const renderFn = isFormItem ? FormItem : Renderer;
  const keyName = rendererName || type;

  if (type && !rendererSet.has(type)) {
    rendererSet.add(type);
    renderFn({
      type,
    })<any>(class extends React.Component<any, any> {
      // 使用 this.context 来消费最近 ScopedContext 上的值
      static contextType = ScopedContext;

      // 真实组件实例
      control: any;

      // 组件名称描述，方便调试
      displayName = displayName;

      constructor(props: any) {
        super(props);
        this.control = props.outRef || React.createRef();
        const me: any = this;
        const apis = renderApiCreator?.(me);
        apis && Object.keys(apis).forEach((key) => {
          me[key] = apis[key].bind(me);
        });
      }

      componentDidMount(): void {
        const scoped = this.context as IScopedContext;
        scoped.registerComponent(this);
      }

      componentWillUnmount(): void {
        const scoped = this.context as IScopedContext;
        scoped.unRegisterComponent(this);
      }

      getApi = () => this.control.current?.getApi?.() || this.control.current;

      receive = (values: object) => {
        const api = this.control.current?.getApi?.() || this.control.current || {};
        api.receive?.(values);
        udp.debug({ msg: ['receive', values], type: 'log' });
      };

      render() {
        // console.log('[debug] Cmp props:', generateProps(this.props, events));
        return <Cmp {...generateProps(this.props, events)} self={this} outRef={this.control} />;
      }
    });
  }

  if (isPlugin) {
    class CurrentPlugin extends BasePlugin {
      // 这里要跟对应的渲染器名字对应上
      // 注册渲染器的时候会要求指定渲染器名字
      rendererName = keyName;

      // 暂时只支持这个，配置后会开启代码编辑器
      $schema = '/schemas/UnkownSchema.json';

      isBaseComponent = isBaseComponent;

      order = -1;

      // 用来配置名称和描述
      name = name || keyName;

      // tag，决定会在哪个分组下面显示的
      tags = [group || '常用组件'];

      // 拖入组件里面时的初始数据
      scaffold = {
        type: keyName,
        name: keyName.replace('udp-', ''),
        ...scaffold,
      };

      panelJustify = true;

      notRenderFormZone = true;

      isFormItem = !!isFormItem;

      // 用来生成预览图的
      previewSchema = previewSchema || this.scaffold;

      events = events;

      panelBody = panelBodyCreator ? undefined : (panelBody || [
        getSchemaTpl('tabs', panelTabs || getSchemaTpl('commonTpl', { isFormItem })),
      ]);

      panelBodyCreator = panelBodyCreator ? ((context: any) => panelBodyCreator.call(this, context)) : undefined;

      constructor(props: EditorManager) {
        super(props);
        const me = this as any;
        Object.keys(payload).forEach((key: any) => {
          me[key] = payload[key];
          if (key === 'regions') {
            me.scaffold.regions = payload[key].map(({ key }: any) => key);
          }
        });

        if (!me.type) {
          me.type = groupType || 'sys-custom';
        }
        me.aa = 1
      }

      getRendererInfo(context) {
        const info: any = super.getRendererInfo(context);
        if (info && designType === 'extension' && context.schema.name && context.schema.name.indexOf('user_ext_') !== 0) {
          info.removable = false;
        }
        return info;
      }
    }

    return CurrentPlugin;
  }
  return emptyFn;
}
